import { geFormatValue, loadResourceConfig } from './SpringResource';
import { Clazz } from './SpringType';
import { isFunction } from './util/shared';

//设置默认配置
loadResourceConfig({
  'j-spring': {
    log: {
      level: 'debug',
    },
  },
});

type LogCallback = (
  error?: any,
  level?: string,
  message?: string,
  meta?: any
) => void;

type LeveledLogMethod = {
  (message: string, callback: LogCallback): Logger;
  (message: string, meta: any, callback: LogCallback): Logger;
  (message: string, ...meta: any[]): Logger;
  (message: any): Logger;
  (infoObject: object): Logger;
};

export class Logger {
  error: LeveledLogMethod;
  warn: LeveledLogMethod;
  help: LeveledLogMethod;
  data: LeveledLogMethod;
  info: LeveledLogMethod;
  debug: LeveledLogMethod;
  prompt: LeveledLogMethod;
  http: LeveledLogMethod;
  verbose: LeveledLogMethod;
  input: LeveledLogMethod;
  silly: LeveledLogMethod;
}

const isOpenLog = () => {
  return geFormatValue('j-spring.log.level', String) !== 'off';
};

const levelDic = [
  'error',
  'warn',
  'help',
  'data',
  'info',
  'debug',
  'prompt',
  'http',
  'verbose',
  'input',
  'silly',
];

/**
 * 支持多级别打印，例如({ 'j-spring.log.level': 'info,http' })
 *  info代表最低打印级别
 *  http 为追加的额外低级别，可存在多个
 *
 * 日志校验  只有当程序员主动调用的时候才能初始化
 */
class LogVerify {
  constructor(isOpenLog: boolean, userLevelConfig: String) {
    this.isOpenLog = isOpenLog;
    this.userLevelConfig = userLevelConfig;
    this.allowPrintLevelList = this.userLevelConfig.split(',');
    this.lowLevelIndex = levelDic.indexOf(this.allowPrintLevelList[0]);
    if (this.isOpenLog && this.lowLevelIndex === -1) {
      throw `日志级别初始化错误:${userLevelConfig}`;
    }
  }
  //是否开启了日志
  isOpenLog: boolean;
  //用户设置的日志
  userLevelConfig: String;
  //允许打印的日志级别
  allowPrintLevelList: string[] = [];
  //当前级别
  lowLevelIndex: number;

  /**
   * 校验当前level是否允许打印！
   *
   */
  isPrint(level: string): boolean {
    //关闭日志的情况 允许打印
    if (!this.isOpenLog) return false;
    //存在于允许打印的日志级别 用于打印追加的低级别！
    if (this.allowPrintLevelList.indexOf(level) > -1) return true;
    //当前级别优先级高于最低级别
    return levelDic.indexOf(level) < this.lowLevelIndex;
  }
}

let logVerify: LogVerify;

function initLogVerify() {
  if (!logVerify) {
    logVerify = new LogVerify(
      isOpenLog(),
      geFormatValue('j-spring.log.level', String)
    );
  }
}

/***
 * methodLevel 当前调用方法的级别
 * configLevel 用户配置的级别
 */
const createMethod = (methodLevel: string) => {
  return (arg: any): Logger => {
    //初始化日志校验配置
    initLogVerify();
    //打印日志
    if (logVerify.isPrint(methodLevel)) {
      if (thridLog) {
        const m = (thridLog as any)[methodLevel];
        if (isFunction(m)) {
          m.apply(thridLog, [arg]);
        } else {
          throw `第三方日志不支持${methodLevel}方法`;
        }
      } else {
        const m = (console as any)[methodLevel] || console.log;
        m.apply(console, [`${methodLevel} => ${arg}`]);
      }
    }
    return springLog;
  };
};

export let springLog: Logger = {
  error: createMethod('error'),
  warn: createMethod('warn'),
  help: createMethod('help'),
  data: createMethod('data'),
  info: createMethod('info'),
  debug: createMethod('debug'),
  prompt: createMethod('prompt'),
  http: createMethod('http'),
  verbose: createMethod('verbose'),
  input: createMethod('input'),
  silly: createMethod('silly'),
};

let thridLog: Logger;

export const setLogger = (log: Logger) => {
  if (isOpenLog()) thridLog = log;
};

export const createDebugLogger = (prefix: string) => (msg: string) => {
  springLog.debug(prefix + msg);
};

export function createLogBean(clazz: Clazz): Logger {
  const log = new Proxy(
    {},
    {
      get: function(_obj, prop) {
        const target = springLog as any;
        return function(arg: any) {
          target[prop](`${clazz.name}.class: ${arg}`);
        };
      },
    }
  );
  return log as Logger;
}

export function isCloseLog(): boolean {
  return geFormatValue('j-spring.log.level', String) === 'off';
}
